package org.oschina.util.jedis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

public class JedisUtil {

	/**
	 * 获得剩余生存时间
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static long ttl(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.ttl(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 返回有序集合内所有成员
	 * @param shardedJedisPool
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public static Set<String> zrange(ShardedJedisPool shardedJedisPool,final String key,final int start,final int end)
	{
		return (Set<String>)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.zrange(key, start, end);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 返回集合内所有成员
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static Set<String> smembers(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (Set<String>)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.smembers(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 设置过期时间
	 * @param shardedJedisPool
	 * @param key
	 * @param timeout
	 * @return
	 */
	public static Long expire(ShardedJedisPool shardedJedisPool,final String key,final int timeout)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.expire(key, timeout);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 增加或减少值
	 * @param shardedJedisPool
	 * @param key
	 * @param field
	 * @param count
	 * @return
	 */
	public static Long incr(ShardedJedisPool shardedJedisPool,final String key,final int count)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.incrBy(key, count);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 增加或减少字段的值
	 * @param shardedJedisPool
	 * @param key
	 * @param field
	 * @param count
	 * @return
	 */
	public static Long hincr(ShardedJedisPool shardedJedisPool,final String key,final String field,final int count)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hincrBy(key, field, count);
			}
		},shardedJedisPool);
	}
	
	/**
	 * hkey是否存在
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static boolean hexists(ShardedJedisPool shardedJedisPool,final String key,final String field)
	{
		return (Boolean)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hexists(key, field);
			}
		},shardedJedisPool);
	}
	
	/**
	 * key是否存在
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static boolean exists(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (Boolean)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.exists(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 设置列表值
	 * @param shardedJedisPool
	 * @param key
	 * @param index
	 * @param value
	 * @param timeout
	 * @return
	 */
	public static String lset(ShardedJedisPool shardedJedisPool,final String key,final int index,final String value,final int timeout)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				String result=jedis.lset(key,index,value);
				expire(jedis, key, timeout);
				return result;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 返回列表长度
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static long llen(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.llen(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 取出列表值
	 * @param shardedJedisPool
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public static List<String> lget(ShardedJedisPool shardedJedisPool,final String key,final int start,final int end)
	{
		return (List<String>)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.lrange(key, start, end);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 取出列表值
	 * @param shardedJedisPool
	 * @param key
	 * @param index
	 * @return
	 */
	public static String lget(ShardedJedisPool shardedJedisPool,final String key,final int index)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.lindex(key, index);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 删除列表一个元素
	 * @param shardedJedisPool
	 * @param key
	 * @param index
	 */
	public static String ldel(ShardedJedisPool shardedJedisPool,final String key,final int index)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.ltrim(key, index, 1);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 获得hash长度
	 * @param shardedJedisPool
	 * @param hkey
	 * @return
	 */
	public static long hlen(ShardedJedisPool shardedJedisPool,final String hkey)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hlen(hkey);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 获得hash中所有key
	 * @param shardedJedisPool
	 * @param hkey
	 * @return
	 */
	public static Set<String> hkeys(ShardedJedisPool shardedJedisPool,final String hkey)
	{
		return (Set<String>)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hkeys(hkey);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 获得节点所有key
	 * @param jedis
	 * @param pattern
	 * @return
	 */
	public static List<String> keys(Jedis jedis,String pattern)
	{
		return new ArrayList(jedis.keys(pattern));
	}
	
	/**
	 * 根据节点IP获得节点
	 * @param shardedJedisPool
	 * @param host
	 * @return
	 */
	public static Object getJedisByHost(ShardedJedisPool shardedJedisPool,final String host,final IJedisCallback callback)
	{
		return execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				List<Jedis> jedisList=new ArrayList(jedis.getAllShards());
				for(Jedis jedisTemp:jedisList)
				{
					if(jedisTemp.getClient().getHost().equals(host))
						return callback.handle(jedisTemp);
				}
				
				return null;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 放入
	 * @param shardedJedisPool
	 * @param key
	 * @param value
	 * @param timeout
	 * @return
	 */
	public static Long rpush(ShardedJedisPool shardedJedisPool,final String key,final String value,final int timeout)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				Long result=jedis.rpush(key,value);
				expire(jedis,key,timeout);
				return result;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 放入
	 * @param shardedJedisPool
	 * @param key
	 * @param value
	 * @param timeout
	 * @return
	 */
	public static Long lpush(ShardedJedisPool shardedJedisPool,final String key,final String value,final int timeout)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				Long result=jedis.lpush(key,value);
				expire(jedis,key,timeout);
				return result;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 取值
	 * @param shardedJedisPool
	 * @param key
	 * @return
	 */
	public static String lpop(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.lpop(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 取值
	 * @param shardedJedisPool
	 * @param key
	 * @param timeout
	 * @return
	 */
	public static String rpop(ShardedJedisPool shardedJedisPool,final String key)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.rpop(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 返回_hash
	 * @param key
	 * @param field
	 * @param shardedJedisPool
	 * @return
	 */
	public static String hget(final String key,final String field,ShardedJedisPool shardedJedisPool)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hget(key,field);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 设置_hash
	 * @param key
	 * @param field
	 * @param value
	 * @param timeout  小于等于0代表不过期
	 * @param shardedJedisPool
	 * @return
	 */
	public static Long hset(final String key,final String field,final String value,final int timeout,ShardedJedisPool shardedJedisPool)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				Long result=jedis.hset(key, field, value);
				expire(jedis,key,timeout);
				return result;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 删除_hash
	 * @param key
	 * @param field
	 * @param shardedJedisPool
	 * @return
	 */
	public static Long hdel(final String key,final String field,ShardedJedisPool shardedJedisPool)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hdel(key,field);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 获得hashKey全部的值
	 * @param key
	 * @param shardedJedisPool
	 * @return
	 */
	public static Map<String,String> hgetAll(final String key,ShardedJedisPool shardedJedisPool)
	{
		return (Map<String,String>)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.hgetAll(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 返回
	 * @param key
	 * @param shardedJedisPool
	 * @return
	 */
	public static String get(final String key,ShardedJedisPool shardedJedisPool)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.get(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 设置
	 * @param key
	 * @param value
	 * @param timeout 小于等于0代表不过期
	 * @param shardedJedisPool
	 * @return
	 */
	public static String set(final String key,final String value,final int timeout,ShardedJedisPool shardedJedisPool)
	{
		return (String)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				String result=jedis.set(key, value);
				expire(jedis,key,timeout);
				return result;
			}
		},shardedJedisPool);
	}
	
	/**
	 * 删除
	 * @param key
	 * @param shardedJedisPool
	 * @return
	 */
	public static Long del(final String key,ShardedJedisPool shardedJedisPool)
	{
		return (Long)execute(new IShardedJedisCallback()
		{
			@Override
			public Object handle(ShardedJedis jedis)
			{
				return jedis.del(key);
			}
		},shardedJedisPool);
	}
	
	/**
	 * 设置过期时间
	 * @param jedis
	 * @param key
	 * @param timeout 0代表不过期
	 */
	public static void expire(ShardedJedis jedis,final String key,final int timeout)
	{
		if(timeout>0 && jedis.ttl(key)==-1)
			jedis.expire(key, timeout);
	}
	
	/**
	 * 处理  自动获得和返还实例
	 * @param callback
	 * @param shardedJedisPool
	 */
	public static Object execute(IShardedJedisCallback callback,ShardedJedisPool shardedJedisPool)
	{
		ShardedJedis jedis=getShardedJedis(shardedJedisPool);
		Object result=callback.handle(jedis);
		returnResource(jedis, shardedJedisPool);
		return result;
	}
	
	/**
	 * 获得一个实例
	 * @param shardedJedisPool
	 * @return
	 */
	public static ShardedJedis getShardedJedis(ShardedJedisPool shardedJedisPool)
	{
		return shardedJedisPool.getResource();
	}
	
	/**
	 * 返还实例
	 * @param jedis
	 * @param shardedJedisPool
	 */
	public static void returnResource(ShardedJedis jedis,ShardedJedisPool shardedJedisPool)
	{
		shardedJedisPool.returnResource(jedis);
	}
	
	/**
	 * 返回对象池
	 * @param hosts
	 * @param maxActive
	 * @param maxIdle
	 * @param maxWait
	 * @param testOnBorrow
	 * @param testOnReturn
	 * @return
	 */
	public static ShardedJedisPool getShardedJedisPool(List<String> hosts,List<String> ports,int maxActive,int maxIdle,int maxWait,boolean testOnBorrow,boolean testOnReturn)
	{
		List<JedisShardInfo> jedisShardList=new ArrayList<JedisShardInfo>();
		for(int i=0,len=hosts.size();i<len;i++)
			jedisShardList.add(getJedisShardInfo(hosts.get(i),ports.get(i)));
		
		return getShardedJedisPool(getJedisPoolConfig(maxActive, maxIdle, maxWait, testOnBorrow, testOnReturn),jedisShardList);
	}
	
	/**
	 * 销毁对象池
	 * @param shardedJedisPool
	 */
	public static void destroyShardedJedisPool(ShardedJedisPool shardedJedisPool)
	{
		shardedJedisPool.destroy();
	}
	
	/**
	 * 返回对象池
	 * @param jedisPoolConfig
	 * @param jedisShardInfo
	 * @return
	 */
	public static ShardedJedisPool getShardedJedisPool(JedisPoolConfig jedisPoolConfig,List<JedisShardInfo> jedisShardInfo)
	{
		return new ShardedJedisPool(jedisPoolConfig,jedisShardInfo);
	}

	/**
	 * 返回分布信息
	 * @param host
	 * @param port
	 * @return
	 */
	public static JedisShardInfo getJedisShardInfo(String host,String port)
	{
		JedisShardInfo jedisShardInfo=new JedisShardInfo(host,Integer.valueOf(port));
		return jedisShardInfo;
	}
	
	/**
	 * 返回配置
	 * @param maxActive
	 * @param maxIdle
	 * @param maxWait
	 * @param testOnBorrow
	 * @param testOnReturn
	 * @return
	 */
	public static JedisPoolConfig getJedisPoolConfig(int maxActive,int maxIdle,int maxWait,boolean testOnBorrow,boolean testOnReturn)
	{
		JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
		jedisPoolConfig.setMaxActive(maxActive);
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWait(maxWait);
		jedisPoolConfig.setTestOnBorrow(testOnBorrow);
		jedisPoolConfig.setTestOnReturn(testOnReturn);
		return jedisPoolConfig;
	}
}